package beanstao.util.store.domainobject;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.json.JSONArray;

import beanstao.util.Dates;
import beanstao.util.Strings;
import beanstao.util.exception.technical.dal.domain.DomainSetException;
import beanstao.util.id.DId;
import beanstao.util.id.Id;
import beanstao.util.json.JsonLib;
import beanstao.util.log.ILog;
import beanstao.util.log.LogHelper;
import beanstao.util.reflect.Mirror;
import beanstao.util.store.IQD;
import beanstao.util.store.database.Fields;
import beanstao.util.store.domainobject.fields.PublicField;
import beanstao.util.store.domainobject.interfaces.IDomain;

import com.google.common.collect.Lists;

/**
 * 针对领域实体对象的抽象类,DA(数据操作)层的核心类
 * 
 * @author beanstao@google.com 
 * @date 2010-09-20 16:45:05
 * @version 2.2
 */
public abstract class Domain implements IDomain, Map<String, Object>, Serializable, ILog
{

	/**
	 * 一个串行版本标识。其中数字后面加上的L表示这是一个long值。通过这种方式来解决不同的版本之间的串行化问题。
	 */
	private static final long serialVersionUID = -3930527199873612095L;

	/**
	 * 针对实体对象的抽象类的构造函数
	 * 
	 * @param columMap
	 *            对象的字段列表
	 */
	public Domain(final Fields fields)
	{
		this.setFields(fields);
	}

	/**
	 * 针对实体对象的抽象类的构造函数
	 * 
	 * @param fields
	 *            对象的字段列表
	 * @param user
	 *            打算持久化本实体的用户的ID
	 */
	public Domain(final Fields fields, final Id modifiorId)
	{
		this.setFields(fields);
		this.setModifior(modifiorId);
	}

	/**
	 * 针对实体对象的抽象类的构造函数
	 * 
	 * @param fields
	 *            对象的字段列表
	 * @param user
	 *            打算持久化本实体的用户的ID
	 */
	public Domain(final Fields fields, final Id modifiorId, final Id newDomainId)
	{
		this.setFields(fields);
		this.setModifior(modifiorId);
		this.setId(newDomainId);
	}

	protected void setFields(final Fields fields)
	{
		if ((fields == null) || (fields.size() < PublicField.PUBLIC_COUNT))
			throw new DomainSetException();
		_fields = fields;
	}

	protected Fields _fields;

	protected boolean _isModified = false;

	public Fields getFields()
	{
		return _fields;
	}

	/**
	 * 返回对象实例在被创建后是否被修改
	 * 
	 * @see beanstao.util.store.domainobject.IDomain#isModifiedByDomain()
	 */
	public boolean isModifiedByDomain()
	{
		return _isModified;
	}

	/**
	 * 获得本实体对象的Class的包装
	 * 
	 * @return
	 */
	public Mirror<?> getMirror()
	{
		return Mirror.me(this);
	}

	/**
	 * DomainObject真实数据存储的位置。
	 */
	protected final HashMap<String, Object> _filedKeyValueMap = new HashMap<String, Object>();

	/**
	 * 返回该实例的JSON字符串
	 * 
	 * @see beanstao.util.interfaces.to.interfaces.IToJson#toJson()
	 */
	public String toJson()
	{
		return JsonLib.fromObject(_filedKeyValueMap).toString();
	}

	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + ((_fields == null) ? 0 : _fields.hashCode());
		result = prime * result + ((_filedKeyValueMap == null) ? 0 : _filedKeyValueMap.hashCode());
		result = prime * result + (_isModified ? 1231 : 1237);
		return result;
	}

	@Override
	public boolean equals(final Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		Domain other = (Domain) obj;
		if (_filedKeyValueMap == null)
		{
			if (other._filedKeyValueMap != null)
				return false;
		}
		else if (!this.getId().equals(other.getId()))
			return false;
		if (_fields == null)
			if (other._fields != null)
				return false;
		if (_isModified != other._isModified)
			return false;
		return true;
	}

	// ==== 开始。实现Map<String, Object>接口 ====

	/**
	 * 清除本类型的所有字段
	 * 
	 * @see java.util.Map#clear()
	 */
	@Override
	public void clear()
	{
		_filedKeyValueMap.clear();
		_isModified = true;
	}

	/**
	 * 返回本类型是否包含指定的字段
	 * 
	 * @see java.util.Map#containsKey(java.lang.Object)
	 */
	@Override
	public boolean containsKey(final Object key)
	{
		return _fields.containsKey((String.valueOf(key)).toLowerCase());
	}

	/**
	 * 返回本类型是否指定的值
	 * 
	 * @see java.util.Map#containsValue(java.lang.Object)
	 */
	@Override
	public boolean containsValue(final Object value)
	{
		return _filedKeyValueMap.containsValue(value);
	}

	/**
	 * 返回本类型实例的键值对的集合
	 * 
	 * @see java.util.Map#entrySet()
	 */
	@Override
	public Set<Map.Entry<String, Object>> entrySet()
	{
		return _filedKeyValueMap.entrySet();
	}

	/**
	 * 返回指定key的字段值
	 * 
	 * @see java.util.Map#get(java.lang.Object)
	 */
	@Override
	public Object get(final Object key)
	{
		if (!this.containsKey(key))
			this.logWarn(String.format("类型 %s 中的字段列表中没有相应的\"%s\"字段的定义。", this.getClass().getSimpleName(), key));
		return _filedKeyValueMap.get(((String) key).toLowerCase());
	}

	/**
	 * 本实例是否为空
	 * 
	 * @see java.util.Map#isEmpty()
	 */
	@Override
	public boolean isEmpty()
	{
		return _filedKeyValueMap.isEmpty();
	}

	/**
	 * 本实例的键的集合(实体对象的字段名的集合)
	 * 
	 * @see java.util.Map#keySet()
	 */
	@Override
	public Set<String> keySet()
	{
		return _filedKeyValueMap.keySet();
	}

	/**
	 * 添加或更改指定key的字段的值<br>
	 * 实际应用前最好使用containsKey方法对键值进行判断。
	 * 
	 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
	 */
	@Override
	public Object put(final String key, final Object value)
	{
		Object object = _filedKeyValueMap.put(key.toLowerCase(), value);
		_isModified = true;
		return object;
	}

	/**
	 * 将指定的Map的值存入本实体相应的字段中
	 * 
	 * @see java.util.Map#putAll(java.util.Map)
	 */
	@Override
	public void putAll(final Map<? extends String, ? extends Object> m)
	{
		for (String key : m.keySet())
			this.put(key.toLowerCase(), m.get(key));
	}

	/**
	 * 将指定Key的字段删除
	 * 
	 * @see java.util.Map#remove(java.lang.Object)
	 */
	@Override
	public Object remove(final Object key)
	{
		if (!this.containsKey(key))
			this.logWarn(String.format("类型 %s 中的字段列表中没有相应的\"%s\"字段的定义。", this.getClass().getSimpleName(), key));
		Object object = _filedKeyValueMap.remove(((String) key).toLowerCase());
		_isModified = true;
		return object;
	}

	/**
	 * 本类型的字段的个数
	 * 
	 * @see java.util.Map#size()
	 */
	@Override
	public int size()
	{
		return _filedKeyValueMap.size();
	}

	/**
	 * 本类型的所有字段的值的集合
	 * 
	 * @see java.util.Map#values()
	 */
	@Override
	public Collection<Object> values()
	{
		return _filedKeyValueMap.values();
	}

	/**
	 * 将值是以Json格式存储的属性解析为字符串强类型的集合
	 */
	@Override
	public List<String> getJsonAttribute(String attrName)
	{
		List<String> result = Lists.newArrayList();
		JSONArray ops = JSONArray.fromObject(_filedKeyValueMap.get(attrName));
		if (ops == null)
			return Lists.newArrayList();
		for (Object op : ops)
			if (!Strings.isEmpty(op.toString()))
				result.add(op.toString());
		return result;
	}

	/**
	 * 判断以Json格式存储的属性中是否存在指定的值
	 * 
	 * @param stationId
	 * @param value
	 * @return
	 */
	public boolean existJsonAttribute(String attrName, Object value)
	{
		String srcOps = (String) _filedKeyValueMap.get(attrName);
		JSONArray resultJson = JSONArray.fromObject(srcOps);
		return resultJson.contains(value);
	}

	// ===== 完成。实现Map<String, Object>接口======

	/**
	 * 添加本实体的Id值
	 * 
	 * @param id
	 *            本实体的Id值
	 */
	public Id getId()
	{
		Object id = this.get(PublicField.ID);
		if (null == id)
		{
			this.logWarn("无法获得ID值，返回一个值为“0”的ID值。");
			return DId.ME("0");
		}
		if (!(id instanceof Id))
			return DId.ME(String.valueOf(id).toLowerCase());
		return (Id) id;
	}

	/**
	 * 设置本实体的Id值
	 * 
	 * @param id
	 *            本实体的Id值
	 */
	public void setId(final Id id)
	{
		this.put(PublicField.ID, DId.ME(id.toString().toLowerCase()));
	}

	/**
	 * 添加本实体记录的创建者
	 * 
	 * @param creator
	 *            本实体记录的创建者
	 */
	public Id getCreator()
	{
		Object id = this.get(PublicField.CREATOE);
		if (null == id)
			return null;
		if (!(id instanceof Id))
			return DId.ME(String.valueOf(id));
		return (Id) id;
	}

	/**
	 * 设置本实体记录的创建者
	 * 
	 * @param creator
	 *            本实体记录的创建者
	 */
	public void setCreator(final Id creator)
	{
		this.put(PublicField.CREATOE, creator);
	}

	/**
	 * 添加本实体记录的最后修改者
	 * 
	 * @param modifior
	 *            本实体记录的最后修改者
	 */
	public Id getModifior()
	{
		Object id = this.get(PublicField.MODIFIOR);
		if (null == id)
			return null;
		if (!(id instanceof Id))
			return DId.ME(String.valueOf(id));
		return (Id) id;
	}

	/**
	 * 设置本实体记录的最后修改者
	 * 
	 * @param modifior
	 *            本实体记录的最后修改者
	 */
	public void setModifior(final String modifior)
	{
		this.put(PublicField.MODIFIOR, modifior);
	}

	/**
	 * 设置本实体记录的最后修改者
	 * 
	 * @param modifior
	 *            本实体记录的最后修改者
	 */
	public void setModifior(final Id modifior)
	{
		this.put(PublicField.MODIFIOR, modifior);
	}

	/**
	 * 添加本实体记录是否是已删除状态
	 * 
	 * @param isDeleted
	 *            本实体记录是否是已删除状态
	 */
	public Boolean getIsDeleted()
	{
		if (this.get(PublicField.IS_DELETED) != null)
		{
			if (this.get(PublicField.IS_DELETED).equals("1"))
				return true;
			else
				return false;
		}
		else
			return false;
	}

	/**
	 * 设置本实体记录是否是已删除状态
	 * 
	 * @param isDeleted
	 *            本实体记录是否是已删除状态
	 */
	public void setIsDeleted(final Boolean isDeleted)
	{
		this.put(PublicField.IS_DELETED, isDeleted);
	}

	/**
	 * 添加本实体记录的创建时间
	 * 
	 * @param createdTime
	 *            本实体记录的创建时间
	 */
	public Date getCreatedTime()
	{
		return (Dates.parse((String) this.get(PublicField.CREATED_TIME)));
	}

	/**
	 * 设置本实体记录的创建时间
	 * 
	 * @param createdTime
	 *            本实体记录的创建时间
	 */
	public void setCreatedTime(final Date createdTime)
	{
		this.put(PublicField.CREATED_TIME, Dates.formatGeneral(createdTime));
	}

	/**
	 * 添加本实体记录的最后修改时间
	 * 
	 * @param modifedTime
	 *            本实体记录的最后修改时间
	 */
	public Date getModifedTime()
	{
		if (this.get(PublicField.MODIFED_TIME) == null)
			return null;
		return Dates.parse(this.get(PublicField.MODIFED_TIME).toString());
	}

	/**
	 * 设置本实体记录的最后修改时间
	 * 
	 * @param modifedTime
	 *            本实体记录的最后修改时间
	 */
	public void setModifedTime(final Date modifedTime)
	{
		this.put(PublicField.MODIFED_TIME, Dates.formatGeneral(modifedTime));
	}

	/**
	 * 添加本实体记录的备注(描述，说明，其他)
	 * 
	 * @param memo
	 *            本实体记录的备注(描述，说明，其他)
	 */
	public String getMemo()
	{
		return (String) this.get(PublicField.MEMO);
	}

	/**
	 * 设置本实体记录的备注(描述，说明，其他)
	 * 
	 * @param memo
	 *            本实体记录的备注(描述，说明，其他)
	 */
	public void setMemo(final String memo)
	{
		this.put(PublicField.MEMO, memo);
	}

	// ====================

	/**
	 * 解析RequestData为指定的Domain。
	 * 
	 * @param <T>
	 * @param domain
	 * @param data
	 * @return
	 */
	public void fromRequest(final IQD data)
	{
		if (null == data)
			this.logWarn("传入参数：IQD 为空，无法解析为DomainObject。位于方法Domain.fromRequest()。");
		for (String key : data.getKeys())
			if (PublicField.ID.equals(key))
			{
				String id = key.toLowerCase();
				if (data.get(id) == null)
					continue;
				if (null == data.get(id).$V())
					continue;
				if (Strings.isEmpty(data.get(id).$V().toString()))
					continue;
				Object idvalue = data.get(id);
				if (null == idvalue)
					continue;
				if (idvalue instanceof Id)
					this.put(key, idvalue);
				else
					this.put(key, DId.ME(data.get(id).$V().toString()));
			}
			else if (this.containsKey(key))
				this.put(key, data.get(key).$V());
	}

	// ============================

	@Override
	public void logDebug(final Object message)
	{
		LogHelper.logDebug(this, message);
	}

	@Override
	public void logDebug(final Object message, final Throwable t)
	{
		LogHelper.logDebug(this, message, t);
	}

	@Override
	public void logError(final Object message)
	{
		LogHelper.logError(this, message);
	}

	@Override
	public void logError(final Object message, final Throwable t)
	{
		LogHelper.logError(this, message, t);
	}

	@Override
	public void logInfo(final Object message)
	{
		LogHelper.logInfo(this, message);
	}

	@Override
	public void logInfo(final Object message, final Throwable t)
	{
		LogHelper.logInfo(this, message, t);
	}

	@Override
	public void logWarn(final Object message)
	{
		LogHelper.logWarn(this, message);
	}

	@Override
	public void logWarn(final Object message, final Throwable t)
	{
		LogHelper.logWarn(this, message, t);
	}

}
